/**
 * 工程知识库收集器 - 学习用户工程的结构和规范
 * 
 * 功能：
 * 1. 扫描指定目录下的多个工程
 * 2. 收集 bundle.json, .gni, .h, .cpp, BUILD.gn 文件
 * 3. 分析测试文件命名和编写模式
 * 4. 保存为知识库，供 UT 生成时使用
 */

import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { Logger } from '../../../../src/logger/Logger';

export interface FileInfo {
    path: string;
    relativePath: string;
    type: 'bundle.json' | 'gni' | 'header' | 'source' | 'test' | 'fuzz' | 'build.gn';
    content?: string;  // 小文件才保存内容
    summary?: string;  // 大文件保存摘要
}

export interface ProjectInfo {
    name: string;  // 工程名（从 bundle.json 读取）
    rootPath: string;
    bundleJson?: any;  // bundle.json 内容
    files: {
        gniFiles: FileInfo[];
        headerFiles: FileInfo[];
        sourceFiles: FileInfo[];
        testFiles: FileInfo[];
        fuzzFiles: FileInfo[];
        buildGnFiles: FileInfo[];
    };
    patterns: {
        testFileNaming: string[];  // 测试文件命名模式
        testDirectories: string[];  // 测试目录
        commonIncludes: string[];  // 常见的头文件引用
        testFrameworks: string[];  // 使用的测试框架（如 gtest, gmock）
    };
}

export interface KnowledgeBase {
    version: string;
    lastUpdated: string;
    learningDirectory: string;
    projects: ProjectInfo[];
    globalPatterns: {
        testFileNaming: string[];
        testDirectories: string[];
        commonTestFrameworks: string[];
    };
}

export class ProjectKnowledgeCollector {
    private readonly MAX_FILE_SIZE = 50 * 1024;  // 50KB，超过这个大小只保存摘要
    private readonly MAX_FILES_PER_TYPE = 20;  // 每种类型最多收集多少个文件
    
    /**
     * 学习指定目录下的所有工程
     */
    async learnFromDirectory(
        directoryPath: string,
        progressCallback?: (message: string, progress: number) => void
    ): Promise<KnowledgeBase> {
        Logger.info(`[ProjectKnowledgeCollector] 📚 开始学习工程结构`);
        Logger.info(`[ProjectKnowledgeCollector]    目录: ${directoryPath}`);
        
        if (!fs.existsSync(directoryPath)) {
            throw new Error(`目录不存在: ${directoryPath}`);
        }
        
        // 初始化知识库
        const knowledgeBase: KnowledgeBase = {
            version: '1.0.0',
            lastUpdated: new Date().toISOString(),
            learningDirectory: directoryPath,
            projects: [],
            globalPatterns: {
                testFileNaming: [],
                testDirectories: [],
                commonTestFrameworks: []
            }
        };
        
        // 查找所有包含 bundle.json 的工程
        const projects = await this.findProjects(directoryPath);
        Logger.info(`[ProjectKnowledgeCollector] 🔍 找到 ${projects.length} 个工程`);
        
        if (progressCallback) {
            progressCallback(`找到 ${projects.length} 个工程`, 10);
        }
        
        // 遍历每个工程，收集信息
        for (let i = 0; i < projects.length; i++) {
            const projectPath = projects[i];
            const progress = 10 + (i / projects.length) * 80;
            
            Logger.info(`[ProjectKnowledgeCollector] 📖 学习工程 ${i + 1}/${projects.length}: ${path.basename(projectPath)}`);
            
            if (progressCallback) {
                progressCallback(`正在学习工程: ${path.basename(projectPath)}`, progress);
            }
            
            try {
                const projectInfo = await this.learnProject(projectPath);
                knowledgeBase.projects.push(projectInfo);
            } catch (error) {
                Logger.error(`[ProjectKnowledgeCollector] ❌ 学习工程失败: ${projectPath}, 错误: ${error}`);
            }
        }
        
        // 分析全局模式
        this.analyzeGlobalPatterns(knowledgeBase);
        
        if (progressCallback) {
            progressCallback(`学习完成！共学习了 ${knowledgeBase.projects.length} 个工程`, 100);
        }
        
        Logger.info(`[ProjectKnowledgeCollector] ✅ 学习完成`);
        Logger.info(`[ProjectKnowledgeCollector]    工程数量: ${knowledgeBase.projects.length}`);
        Logger.info(`[ProjectKnowledgeCollector]    全局测试命名模式: ${knowledgeBase.globalPatterns.testFileNaming.join(', ')}`);
        
        return knowledgeBase;
    }
    
    /**
     * 查找所有工程（包含 bundle.json 的目录）
     */
    private async findProjects(rootPath: string): Promise<string[]> {
        const projects: string[] = [];
        const maxDepth = 3;  // 最多向下搜索3层
        
        const searchDir = (dir: string, depth: number) => {
            if (depth > maxDepth) {
                return;
            }
            
            try {
                const entries = fs.readdirSync(dir, { withFileTypes: true });
                
                // 检查当前目录是否有 bundle.json
                if (entries.some(e => e.isFile() && e.name === 'bundle.json')) {
                    projects.push(dir);
                    return;  // 找到工程根目录，不再向下搜索
                }
                
                // 递归搜索子目录
                for (const entry of entries) {
                    if (entry.isDirectory()) {
                        // 跳过一些常见的非工程目录
                        if (!['node_modules', '.git', 'out', 'dist', 'build'].includes(entry.name)) {
                            searchDir(path.join(dir, entry.name), depth + 1);
                        }
                    }
                }
            } catch (error) {
                Logger.warn(`[ProjectKnowledgeCollector] ⚠️ 读取目录失败: ${dir}`);
            }
        };
        
        searchDir(rootPath, 0);
        return projects;
    }
    
    /**
     * 学习单个工程
     */
    private async learnProject(projectPath: string): Promise<ProjectInfo> {
        Logger.info(`[ProjectKnowledgeCollector]   📂 扫描工程: ${projectPath}`);
        
        // 读取 bundle.json
        const bundleJsonPath = path.join(projectPath, 'bundle.json');
        let bundleJson: any = null;
        let projectName = path.basename(projectPath);
        
        if (fs.existsSync(bundleJsonPath)) {
            try {
                const content = fs.readFileSync(bundleJsonPath, 'utf-8');
                bundleJson = JSON.parse(content);
                projectName = bundleJson.name || projectName;
                Logger.info(`[ProjectKnowledgeCollector]      工程名: ${projectName}`);
            } catch (error) {
                Logger.warn(`[ProjectKnowledgeCollector]      ⚠️ 解析 bundle.json 失败`);
            }
        }
        
        // 初始化工程信息
        const projectInfo: ProjectInfo = {
            name: projectName,
            rootPath: projectPath,
            bundleJson,
            files: {
                gniFiles: [],
                headerFiles: [],
                sourceFiles: [],
                testFiles: [],
                fuzzFiles: [],
                buildGnFiles: []
            },
            patterns: {
                testFileNaming: [],
                testDirectories: [],
                commonIncludes: [],
                testFrameworks: []
            }
        };
        
        // 扫描文件
        await this.scanDirectory(projectPath, projectPath, projectInfo);
        
        // 分析模式
        this.analyzeProjectPatterns(projectInfo);
        
        Logger.info(`[ProjectKnowledgeCollector]      📊 文件统计:`);
        Logger.info(`[ProjectKnowledgeCollector]         .gni: ${projectInfo.files.gniFiles.length}`);
        Logger.info(`[ProjectKnowledgeCollector]         .h: ${projectInfo.files.headerFiles.length}`);
        Logger.info(`[ProjectKnowledgeCollector]         .cpp: ${projectInfo.files.sourceFiles.length}`);
        Logger.info(`[ProjectKnowledgeCollector]         test: ${projectInfo.files.testFiles.length}`);
        Logger.info(`[ProjectKnowledgeCollector]         fuzz: ${projectInfo.files.fuzzFiles.length}`);
        Logger.info(`[ProjectKnowledgeCollector]         BUILD.gn: ${projectInfo.files.buildGnFiles.length}`);
        
        return projectInfo;
    }
    
    /**
     * 递归扫描目录
     */
    private async scanDirectory(
        currentPath: string,
        projectRoot: string,
        projectInfo: ProjectInfo,
        depth: number = 0
    ): Promise<void> {
        const maxDepth = 10;
        if (depth > maxDepth) {
            return;
        }
        
        try {
            const entries = fs.readdirSync(currentPath, { withFileTypes: true });
            
            for (const entry of entries) {
                const fullPath = path.join(currentPath, entry.name);
                
                if (entry.isDirectory()) {
                    // 跳过某些目录
                    if (['node_modules', '.git', 'out', 'dist'].includes(entry.name)) {
                        continue;
                    }
                    
                    // 递归扫描子目录
                    await this.scanDirectory(fullPath, projectRoot, projectInfo, depth + 1);
                } else if (entry.isFile()) {
                    // 处理文件
                    await this.processFile(fullPath, projectRoot, projectInfo);
                }
            }
        } catch (error) {
            Logger.warn(`[ProjectKnowledgeCollector] ⚠️ 扫描目录失败: ${currentPath}`);
        }
    }
    
    /**
     * 处理单个文件
     */
    private async processFile(
        filePath: string,
        projectRoot: string,
        projectInfo: ProjectInfo
    ): Promise<void> {
        const fileName = path.basename(filePath);
        const relativePath = path.relative(projectRoot, filePath);
        const ext = path.extname(fileName);
        
        // 判断文件类型
        let fileType: FileInfo['type'] | null = null;
        let targetArray: FileInfo[] | null = null;
        
        if (fileName === 'BUILD.gn') {
            fileType = 'build.gn';
            targetArray = projectInfo.files.buildGnFiles;
        } else if (ext === '.gni') {
            fileType = 'gni';
            targetArray = projectInfo.files.gniFiles;
        } else if (ext === '.h' || ext === '.hpp') {
            fileType = 'header';
            targetArray = projectInfo.files.headerFiles;
        } else if (ext === '.cpp' || ext === '.cc' || ext === '.c') {
            // 判断是测试文件还是普通源文件
            if (relativePath.includes('test') && this.isTestFile(fileName)) {
                fileType = 'test';
                targetArray = projectInfo.files.testFiles;
            } else if (relativePath.includes('fuzz')) {
                fileType = 'fuzz';
                targetArray = projectInfo.files.fuzzFiles;
            } else {
                fileType = 'source';
                targetArray = projectInfo.files.sourceFiles;
            }
        }
        
        // 如果是我们关心的文件类型，并且数量未超限
        if (fileType && targetArray && targetArray.length < this.MAX_FILES_PER_TYPE) {
            const fileInfo = await this.readFileInfo(filePath, relativePath, fileType);
            targetArray.push(fileInfo);
        }
    }
    
    /**
     * 读取文件信息
     */
    private async readFileInfo(
        filePath: string,
        relativePath: string,
        type: FileInfo['type']
    ): Promise<FileInfo> {
        const fileInfo: FileInfo = {
            path: filePath,
            relativePath,
            type
        };
        
        try {
            const stats = fs.statSync(filePath);
            
            if (stats.size <= this.MAX_FILE_SIZE) {
                // 小文件：保存完整内容
                fileInfo.content = fs.readFileSync(filePath, 'utf-8');
            } else {
                // 大文件：只保存摘要（前 100 行）
                const content = fs.readFileSync(filePath, 'utf-8');
                const lines = content.split('\n').slice(0, 100);
                fileInfo.summary = lines.join('\n') + '\n... (文件太大，省略剩余内容)';
            }
        } catch (error) {
            Logger.warn(`[ProjectKnowledgeCollector] ⚠️ 读取文件失败: ${filePath}`);
        }
        
        return fileInfo;
    }
    
    /**
     * 判断是否是测试文件
     */
    private isTestFile(fileName: string): boolean {
        const testPatterns = [
            /_test\.(cpp|cc)$/,
            /_unittest\.(cpp|cc)$/,
            /test_.*\.(cpp|cc)$/,
            /_gtest\.(cpp|cc)$/,
        ];
        
        return testPatterns.some(pattern => pattern.test(fileName));
    }
    
    /**
     * 分析单个工程的模式
     */
    private analyzeProjectPatterns(projectInfo: ProjectInfo): void {
        // 分析测试文件命名模式
        const testFileNames = projectInfo.files.testFiles.map(f => path.basename(f.path));
        const namingPatterns = new Set<string>();
        
        for (const name of testFileNames) {
            if (name.endsWith('_test.cpp') || name.endsWith('_test.cc')) {
                namingPatterns.add('*_test.cpp');
            } else if (name.endsWith('_unittest.cpp') || name.endsWith('_unittest.cc')) {
                namingPatterns.add('*_unittest.cpp');
            } else if (name.startsWith('test_')) {
                namingPatterns.add('test_*.cpp');
            }
        }
        
        projectInfo.patterns.testFileNaming = Array.from(namingPatterns);
        
        // 分析测试目录
        const testDirs = new Set<string>();
        for (const testFile of projectInfo.files.testFiles) {
            const dir = path.dirname(testFile.relativePath);
            testDirs.add(dir);
        }
        projectInfo.patterns.testDirectories = Array.from(testDirs);
        
        // 分析常见的 include
        const includes = new Set<string>();
        for (const file of [...projectInfo.files.testFiles, ...projectInfo.files.sourceFiles].slice(0, 50)) {
            if (file.content) {
                const includeRegex = /#include\s+[<"]([^>"]+)[>"]/g;
                let match;
                while ((match = includeRegex.exec(file.content)) !== null) {
                    includes.add(match[1]);
                }
            }
        }
        projectInfo.patterns.commonIncludes = Array.from(includes).slice(0, 50);
        
        // 分析测试框架
        const frameworks = new Set<string>();
        for (const testFile of projectInfo.files.testFiles) {
            if (testFile.content) {
                if (testFile.content.includes('gtest/gtest.h') || testFile.content.includes('TEST_F') || testFile.content.includes('TEST(')) {
                    frameworks.add('gtest');
                }
                if (testFile.content.includes('gmock/gmock.h') || testFile.content.includes('MOCK_METHOD')) {
                    frameworks.add('gmock');
                }
            }
        }
        projectInfo.patterns.testFrameworks = Array.from(frameworks);
    }
    
    /**
     * 分析全局模式
     */
    private analyzeGlobalPatterns(knowledgeBase: KnowledgeBase): void {
        const allTestNaming = new Set<string>();
        const allTestDirs = new Set<string>();
        const allFrameworks = new Set<string>();
        
        for (const project of knowledgeBase.projects) {
            project.patterns.testFileNaming.forEach(p => allTestNaming.add(p));
            project.patterns.testDirectories.forEach(d => allTestDirs.add(d));
            project.patterns.testFrameworks.forEach(f => allFrameworks.add(f));
        }
        
        knowledgeBase.globalPatterns.testFileNaming = Array.from(allTestNaming);
        knowledgeBase.globalPatterns.testDirectories = Array.from(allTestDirs);
        knowledgeBase.globalPatterns.commonTestFrameworks = Array.from(allFrameworks);
    }
}

